package demo2;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 姚东名
 * Date: 2024-06-11
 * Time: 13:04
 */

import com.sun.org.apache.xpath.internal.objects.XString;

/**
 * 包装类：
 * 在Java中，由于基本数据类型不是继承于Object，为了在泛型代码中可以支持基本数据类型，Java给每个基本数据类型都对应了一个包装类型。
 * 除了Integer和Character，其余基本数据类型的包装类都是首字母大写。
 *
 * 装箱/装包：自动装箱 显示装箱 什么是装箱：把基本数据类型 变成包装类型 的过程叫装箱
 * 拆箱/拆包：自动拆箱 显示拆包 什么是拆箱：把包装类型 变成基本数据类型 的过程叫拆箱
 */
class MyArray {
    /**
     * 引出泛型：
     * 1.以前学过的数组，只能存放指定类型的元素，例如：
     *  int[] array = new int[10];  double[] array = new double[10];
     * 2.所有类的父类，默认为Object类，数组是否可以创建为Object？
     */
    //成员变量：
    public Object[] array = new Object[10];
    //成员方法：输出
    public Object getValue(int pos) {
        return array[pos];
    }
    //成员方法：输入
    public void setValue(int pos, Object val) {
        array[pos] = val;
    }
}
class MyArray1<E extends Number> {
    /**
     * 3.泛型的上界
     * 在定义泛型的时候，有时候需要对传入的类型变量做一定的约束，可以通过类型边界来约束
     * 语法：
     * class 泛型类名称<类型形参 extends 类型边界> {...}
     * class MyArray1<E extends Number> {...} :只接受Number的子类作为E的类型实参
     */
    /**
     * 2.代码解释：
     * 类名后面的<E>代表占位符，当前表示类是一个泛型类
     * 了解：【规范】类型形参一般使用一个大写字母表示，常用的名称有：
     * - E表示Element
     * - K表示Key
     * - V表示Value
     * - N表示Number
     * - T表示Type
     * - S、U、V等等第一、第二、第三、第四个类型
     */
    /**
     * 1.引出泛型：
     * 1.以前学过的数组，只能存放指定类型的元素，例如：
     *  int[] array = new int[10];  double[] array = new double[10];
     * 2.所有类的父类，默认为Object类，数组是否可以创建为Object？
     */
    /**
     * 泛型的语法：
     * class 泛型类名称<类型形参列表> {//这里可以使用类型参数}
     */
    //成员变量：
    public Object[] array = new Object[10];
    //成员方法：输出
    public E getValue(int pos) {
        return (E)array[pos];//这里需强制类型转换，在main方法就不需要了
    }
    //成员方法：输入
    public void setValue(int pos, E val) {//把成员变量变成E类型
        array[pos] = val;
    }
}
public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test);//demo2.Test@1b6d3586

        MyArray1<Integer> myArray1 = new MyArray1<Integer>();
        System.out.println(myArray1);//demo2.MyArray1@4554617c
        /**
         * 泛型到底是怎么进行  编译的？
         * 泛型是编译时期的一种机制，在运行的时候 没有泛型的概念。【JVM当中没有泛型的概念】
         *从 demo2.MyArray1@4554617c 这里可以看出：
         * 此时<>当中的内容不参与类型的组成 -> 在编译完成的时候，E被擦除为Object类型了
         */
    }
    public static void main5(String[] args) {
        //泛型的引用：
        MyArray1<Integer> myArray1 = new MyArray1<Integer>();//new MyArray1<Integer>();也行，可以把后面尖括号的类型省略掉
        myArray1.setValue(0, 11);//自动类型检查
        Integer ret = myArray1.getValue(0);//自动类型的转换
        System.out.println(ret);
        System.out.println("=========");

       /* MyArray1<String> myArray11 = new MyArray1<>();
        myArray11.setValue(1, "hello world");
        String s = myArray11.getValue(1);
        System.out.println(s);*/
        /**
         * 小结：
         * 1. 泛型是将数据类型参数化，进行传递
         * 2. 使用<E>表示当前类是一个泛型类
         * 3. 泛型目前为止的优点》数据类型参数化、编译时自动类型检查转换
         */
    }
    public static void main4(String[] args) {
        //实例化一个myArray对象：
        MyArray myArray = new MyArray();
        myArray.setValue(0, 11);
        System.out.println(myArray.getValue(0));
        //一定得进行强制类型转换：myArray对象的类型是Object，而ret是整型 发生了
        int ret = (int)myArray.getValue(0);

        myArray.setValue(1, "hello world");
        System.out.println(myArray.getValue(1));
        String s = (String)myArray.getValue(1);

        System.out.println("===========");
        System.out.println(ret);
        System.out.println(s);
        /**
         * 问题：以上代码实现后发现
         * 1.任何类型都可以存放
         * 2.1号下标本身就是字符串，但是编译报错，必须进行强制类型转换
         * 虽然在这种情况下，当前数组任何数据类型都可以存放，但是，在更多情况下，希望它只能持有一种数据类型，而不是同时持有这么多类型。所有泛型的主要目标是：指定当前的容器，要持有什么样的数据类型，就让编译器去检查，此时，就需要把数据类型，作为参数传递。需要什么类型，就传什么数据类型。
         */
    }
    public static void main3(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);//true

        Integer c = 200;
        Integer d = 200;
        System.out.println(c == d);//false
        /**
         * 为什么一个是true 一个是false?
         * 这个过程发生了自动装箱的行为：
         * public static Integer valueOf(int i) {
         *         if (i >= IntegerCache.low && i <= IntegerCache.high)
         *             return IntegerCache.cache[i + (-IntegerCache.low)];
         *         return new Integer(i);
         *}
         * low的值为-128：[i + (-IntegerCache.low)]-> -128 + -(-128) == 0
         * high的值为127: [i + (-IntegerCache.low)]-> 127 + -(-128) == 255
         *
         * 所以下标为[0,255)的 都被装在一个数组中了 拿出来 就是一个值 -> a == b：true
         * 所以下标不为[0,255)的 都会创建一个新对象 拿两个对象的引用来比 -> c == d：false
         */
    }
    public static void main2(String[] args) {
        Integer i = 10;
        int b = i;//自动拆箱

        int c = i.intValue();//显示拆箱

        double d = i.doubleValue();
        System.out.println(i);//10
        System.out.println(b);//10
        System.out.println(c);//10
        System.out.println(d);//10.0
    }
    public static void main1(String[] args) {
        int a = 10;
        Integer i = a;//自动装箱
        Integer ii = Integer.valueOf(a);//显示装箱

        System.out.println(i);//10
        System.out.println(ii);//10
        //不同数据类型 也是可以的
        double d = Double.valueOf(a);
        System.out.println(d);//10.0
    }
}
